package main


import(
	"fmt"
	"encoding/json"
	"net/http"
	//"io/ioutil"
	"github.com/go-redis/redis"
	"time"
	"github.com/gin-gonic/gin"
	"strconv"
	"strings"
	log "github.com/jeanphorn/log4go"
	//"github.com/gin-gonic/gin/binding"
)

type OnlineUser struct{
	Uid string `form:"uid" json:"uid" binding:"required"`
	Name string `form:"name" json:"name" binding:"required"`
	From string `form:"from" json:"from" binding:"required"`
	Amt string `form:"amt" json:"amt" binding:"required"`
	Account string `form:"account" json:"account" binding:"required"`
	Logintm int `form:"logintm" json:"logintm" binding:"required"`
	Ip string `form:"ip" json:"ip" binding:"required"`
	Area string `form:"area" json:"area" binding:"required"`
	Cdesk string `form:"cdesk" json:"cdesk"`
	Proxy string `json:"proxy"`
	Ancestorlist string `json:"ancestorlist"`
}

type UpdateUser struct{
	Uid string `form:"uid" json:"uid" binding:"required"`
	Amt string `form:"amt" json:"amt"`
	Cdesk string `form:"cdesk" json:"cdesk"`
}
type OfflineUser struct{
	Uid string `form:"uid" json:"uid" binding:"required"`
}

type RevMsg struct{
	flag string
	args *map[string]interface{}
}

type QueryArgs struct{
	Uid string `form:"uid" json:"uid" binding:"required"`
	Type int `form:"type" json:"type" binding:"required"`
}

type Rev struct{
	C chan RevMsg
	Count int
	Pipe redis.Pipeliner
}

func (this *Rev) start() {
	for {
		select {
		case msg := <- this.C:
			this.Count++
			this.UpdateData(&msg)
		case  <- time.After(time.Second * 10):
			if this.Count >= 0{
				Ex, Err := this.Pipe.Exec()
				if Err != nil{
					log.Error("写入失败",Ex, Err)
				}
				this.Count = 0
				//fmt.Println("可以写入了", Ex, this.AllOnline())
				//this.ShowAllOnline()
			}
		}
	}	
}

func (this *Rev) UpdateData(msg *RevMsg) {
	args := *msg.args
	switch msg.flag{
	case "online":
		//fmt.Println("写入", msg.flag, Config.Normal.UidOnline + args["uid"].(string), args)
		//abc := map[string]string{"uid":"A0096811", "amt":"100", "account":"3334333", "ancestorlist":"A001|A0096809|A0096811"}
		this.Pipe.HMSet( Config.Normal.UidOnline + args["uid"].(string), args).Err()
	case "update":	
		//fmt.Println("写入", msg.flag)
		this.Pipe.HMSet( Config.Normal.UidOnline + args["uid"].(string), args).Err()
	case "offline":	
		//fmt.Println("写入", msg.flag)
		this.Pipe.Del( Config.Normal.UidOnline + args["uid"].(string)).Err()
	case "delall":	
		//fmt.Println("写入", msg.flag)
		list := this.AllOnline()
		for _, uid := range list {
			this.Pipe.Del( uid ).Err() 
		}
	case "checkonline":	
		list := this.AllOnline()
		for _, uid := range list {
			if _, ok := args[uid]; ok != true{
				this.Pipe.Del( uid ).Err() 
			}
			
		}
	}
	//fmt.Println("Exec", msg.flag)
	//t, e := redisPipe.Exec()
	//fmt.Println("Exec", t, "============", e)
	if this.Count >= 5{
		_, Err := this.Pipe.Exec()
		if Err != nil{
			log.Error("写入失败", Err)
		}
		this.Count = 0
		//fmt.Println("可以写入了")
	}

}

func (this *Rev) AllOnline() (List []string){
	//fmt.Fprintln(w, "hello world")
	List, err := redisDb.Keys(Config.Normal.UidOnline + "*").Result()
	if err != nil{
		log.Error("查询左右在线出错", err)
	}
	return
	
}

func (this *Rev) ShowAllOnline(){
	// List := this.AllOnline()
	// for i := 0; i < len(List); i++ {
	// 	data, e := redisDb.HGetAll(List[i]).Result()
	// 	//log.Error("==================", data, e)
	// }
	
}

func (this *Rev) Online(c *gin.Context){
	//fmt.Println("2监听==============================")
	
	defer c.String(http.StatusOK, "ok")

	//i, errA := c.ShouldBindBodyWith(&reqBody, )
	//n, _ := c.Header.Read(buf)
	
	var reqBody OnlineUser
	err := c.BindJSON(&reqBody)
	if err != nil{
		log.Error("登录在线有问题", reqBody, err)
		return
	}
	//fmt.Println("==========", err, "====", reqBody)
	Proxy, Ancestorlist := dbDao.GetUserProxy(reqBody.Uid)
	reqBody.Proxy = Proxy
	reqBody.Ancestorlist = Ancestorlist
	if len(reqBody.Cdesk) == 0 {
        reqBody.Cdesk = "未入台"
    }
	//fmt.Println("==========", err, "====", reqBody)
	//fmt.Println(Proxyname, Ancestorlist)
	data := make(map[string]interface{}, 9)
	data["uid"] = reqBody.Uid
	data["name"] = reqBody.Name
	data["from"] = reqBody.From
	data["amt"] = reqBody.Amt
	data["account"] = reqBody.Account
	data["logintm"] = reqBody.Logintm
	data["cdesk"] = reqBody.Cdesk
	data["proxy"] = reqBody.Proxy
	data["ancestorlist"] = reqBody.Ancestorlist
	data["ip"] = reqBody.Ip
	data["area"] = reqBody.Area
	this.C <- RevMsg{flag : "online", args : &data}
	//buf := make([]byte, 1024)
	//n, _ := c.Request.Body.Read(buf)
	//jsonData := string(buf[0:n])
	//fmt.Println(jsonData)
	//var res map[string]interface{}

	//jErr := json.Unmarshal(buf[0:n], &res)
	//if jErr != nil {
	//	fmt.Println("==========", jErr)
	//}
	//fmt.Println(res)
	
	//if  errA != nil {
	//	fmt.Println(string(buf[0:n]), abc)
	//  // Always an error is occurred by this because c.Request.Body is EOF now.
	//  }
	//	fmt.Println(reqBody)
	//fmt.Fprintln(w, "hello world")
	//fmt.Fprintln(w, "Online")
}

func (this *Rev) Update(c *gin.Context){
	defer c.String(http.StatusOK, "ok")
	//fmt.Fprintln(w, "hello world")
	var reqBody UpdateUser
	err := c.BindJSON(&reqBody)
	if err != nil{
		log.Error("更新在线有问题", err)
		return
	}
	data := make(map[string]interface{})
	data["uid"] = reqBody.Uid
	if len(reqBody.Amt) > 0 {
		data["amt"] = reqBody.Amt
	}
	if len(reqBody.Cdesk) > 0 {
		data["cdesk"] = reqBody.Cdesk
	}
	this.C <- RevMsg{flag : "update", args : &data}
	
}

func (this *Rev) Offline(c *gin.Context){
	defer c.String(http.StatusOK, "ok")
	//fmt.Fprintln(w, "hello world")
	var reqBody OfflineUser
	err := c.BindJSON(&reqBody)
	if err != nil{
		log.Error("更新下线有问题", err)
		return
	}
	data := make(map[string]interface{})
	data["uid"] = reqBody.Uid
	this.C <- RevMsg{flag : "offline", args : &data}
	
}


func (this *Rev) Delall(c *gin.Context){
	defer c.String(http.StatusOK, "ok")
	data := make(map[string]interface{})
	this.C <- RevMsg{flag : "delall", args : &data}
	//fmt.Fprintln(w, "hello world")
	
}


func (this *Rev) Checkonline(c *gin.Context){
	//fmt.Fprintln(w, "hello world")
	defer c.String(http.StatusOK, "ok")
	buf := make([]byte, 10240)
	n, _ := c.Request.Body.Read(buf)
	//jsonData := string(buf[0:n])
	//fmt.Println(jsonData)
	var reqBody map[string]interface{}
	err := json.Unmarshal(buf[0:n], &reqBody)
	if err != nil {
		fmt.Println("矫正获取数据出错", err)
	}
	this.C <- RevMsg{flag : "checkonline", args : &reqBody}

}

func (this *Rev) QueryOnline(c *gin.Context){
	//fmt.Fprintln(w, "hello world")	
	var reqBody QueryArgs
	err := c.BindJSON(&reqBody)
	if err != nil{
		log.Error("查询数据出错", err)
		return
	}
	List := this.AllOnline()
	UserList := make([]interface{}, 0)
	for i := 0; i < len(List); i++ {
		user, _ := redisDb.HGetAll(List[i]).Result()
		if  _, ok := user["cdesk"]; !ok{
            user["cdesk"] = "未入台"
        }
		UserList = append(UserList, user)
	}
	if reqBody.Type == 3 || reqBody.Type == 9 {
		flash, ios, android, h5, allamt := this.SumOnline(UserList)
		c.JSON(http.StatusOK, gin.H{"error_code" : 0, "data": UserList, "flash": flash, "ios": ios, "android" : android, "h5" : h5, "allamt": allamt, "sEcho":0, "recordsTotal":len(UserList), "recordsFiltered":len(UserList)})
	}else{
		UserList2 := make([]interface{}, 0)
		for _, u1 :=  range UserList {
			//fmt.Printf("%T", u1)
			u := u1.(map[string]string)
			ancestorstr, aok := u["ancestorlist"]
			if aok{
				if isDes := strings.Index(ancestorstr, reqBody.Uid + "|"); isDes > -1{
					UserList2 = append(UserList2, u)
				}
			}
		}
		flash, ios, android, h5, allamt := this.SumOnline(UserList2)
		fmt.Println(UserList2)
		c.JSON(http.StatusOK, gin.H{"error_code" : 0, "data": UserList2, "flash": flash, "ios": ios, "android" : android, "h5" : h5, "allamt": allamt, "sEcho":0, "recordsTotal":len(UserList2), "recordsFiltered":len(UserList2)})
	}
	

}

func (this *Rev) SumOnline(UserList []interface{}) (flash int, ios int, android int, h5 int, allamt int){
	for _, u1 :=  range UserList {
		u := u1.(map[string]string)
        switch from, _ := u["from"]; from {
            case "android":
                android++
            case "ios":
                ios++
            case "h5":
                h5++
            default:
                flash++
        }
        if amt, ok := u["amt"]; ok{
        	if amtNum, err := strconv.Atoi(amt); err == nil{
        		allamt = allamt + amtNum
        	} 
        }
		
	}
	return
}


